#ifndef     __RT_PROMISE_TYPE2_H
#define     __RT_PROMISE_TYPE2_H

#include "./result2.h"
#include <coroutine>

namespace rt {

template <typename PROMISE>
struct FinalAwaiter2 {

    constexpr bool await_ready() const noexcept {
        return false;
    }

    void await_suspend(std::coroutine_handle<PROMISE> handle) noexcept {
        PROMISE& promise = handle.promise();
        promise.resume_parent();
    }

    void await_resume() noexcept {}
};

template <typename TASK, typename PROMISE, typename T = void>
class PromiseType2Base {

public:
    using THIS = PromiseType2Base<TASK, T>;

    TASK get_return_object() noexcept {
        return { std::coroutine_handle<PROMISE>::from_promise(* static_cast<PROMISE *>(this) ) };
    }

    std::suspend_never initial_suspend() noexcept {
        return {};
    }

    void unhandled_exception() noexcept {
        m_result.set_err(std::current_exception());
    }

    FinalAwaiter2<PROMISE> final_suspend() noexcept {
        return {};
    }

    void resume_parent() {
        if (m_parent_handle) {
            m_parent_handle.resume();
        }
    }

    void set_parent(std::coroutine_handle<> h) {
        m_parent_handle = h;
    }

    T get() {
        if constexpr (std::is_void_v<T>) {
            m_result.get();
        } else {
            return m_result.get();
        }
    }

protected:
    Result2<T> m_result;
    std::coroutine_handle<> m_parent_handle;
};

template <typename TASK, typename T = void>
class PromiseType2 : public PromiseType2Base<TASK, PromiseType2<TASK, T>, T> {

public:
    void return_value(T&& value) noexcept {
        this->m_result.set_value( std::move(value) );
    }

    void return_value(const T& value) noexcept {
        this->m_result.set_value( value );
    }

};

template <typename TASK>
class PromiseType2<TASK, void> : public PromiseType2Base<TASK, PromiseType2<TASK, void>, void> {

public:
    void return_void() noexcept {
        this->m_result.set_value();
    }
};


}



#endif
